package com.mxw.account.controller;

import cn.hutool.core.collection.CollUtil;
import com.mxw.account.dto.AccountDTO;
import com.mxw.account.mapper.AccountRepository;
import com.mxw.account.mapper.domain.Account;
import com.mxw.account.mapper.domain.AccountEntity;
import com.mxw.account.service.AccountService;
import com.mxw.account.service.strategy.document.DocumentStrategyContainer;
import com.mxw.commons.errorcode.GlobalErrorCode;
import com.mxw.commons.exception.CustomException;
import com.mxw.commons.restful.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/** @Description @Author RingKo @Date 2021/8/23 22:13 @Version 1.0 */
@Slf4j
@Validated
@RestController
@RequestMapping(value = "/account")
public class AccountController {
  @Resource private AccountService accountService;
  @Resource private AccountRepository accountRepository;
  @Resource private DocumentStrategyContainer documentStrategyContainer;

  @CrossOrigin(origins = {"http://192.168.1.129:9010", "http://localhost:9010"})
  @GetMapping("/getByCode")
  public Result<AccountDTO> getByCode(@RequestParam String accountCode) {
    log.info("get account detail,accountCode is :{}", accountCode);
    Account account = accountService.selectByCode(accountCode);
    AccountDTO accountDTO =
        AccountDTO.builder()
            .accountCode(account.getAccountCode())
            .accountName(account.getAccountName())
            .amount(account.getAmount())
            .build();
    return Result.respond(accountDTO);
  }

  @PostMapping("/insert")
  public Result<String> insert(@RequestBody AccountDTO accountDTO) {
    accountService.saveAccount(accountDTO);
    return Result.respond("来自account的数据。");
  }

  /** @Description: 幂等测试，读写同步锁 TODO:后续优化为分布式锁 */
  @PostMapping("/insert2")
  public Result<String> insert2(@RequestBody AccountDTO accountDTO) throws Exception {
    synchronized (accountDTO.getAccountName().intern()) {
      List<AccountEntity> accountEntities =
          accountRepository.findByAccountName(accountDTO.getAccountName());
      if (CollUtil.isNotEmpty(accountEntities)) {
        throw new CustomException(GlobalErrorCode.DATA_NOT_FOUND, "重复数据");
      } else {
        Thread.sleep(5000);
        accountService.saveAccount(accountDTO);
      }
      return Result.respond("来自account的数据。");
    }
  }

  /** @Description: jpa分页查询测试接口 */
  @GetMapping("/test/{page}/{size}")
  public Result<Page<AccountEntity>> findPage(
      @PathVariable Integer page, @PathVariable Integer size) {
    PageRequest pageRequest =
        PageRequest.of(
            page - 1,
            size,
            Sort.by(Sort.Order.desc("customStatusSorting"))
                .and(Sort.by(Sort.Order.desc("amount")))
                .and(Sort.by(Sort.Order.asc("id"))));
    Page<AccountEntity> accountEntityPage = accountRepository.findAll(pageRequest);
    // 对结果集转换dto的话，可以通过pageImpl。
    return Result.respond(
        new PageImpl<>(
            accountEntityPage.getContent(), pageRequest, accountEntityPage.getTotalElements()));
  }

  /** 测试@Formula对于原生sql的影响 */
  @GetMapping("/test/formula")
  public Result<Page<AccountEntity>> testFormula() {
    Pageable pageable = PageRequest.of(1, 10, Sort.by(Sort.Order.desc("customStatusSorting")));
    Page<AccountEntity> lastAccount = accountRepository.findLastAccount(pageable);
    return Result.respond(lastAccount);
  }

  /** @Description: jpa分页查询测试接口 */
  @GetMapping("/test1/{page}/{size}")
  public Result<AccountDTO> findPage1(@PathVariable Integer page, @PathVariable Integer size) {
    AccountEntity accountEntity =
        accountRepository
            .findById(1)
            .orElseThrow(() -> new CustomException(GlobalErrorCode.DATA_NOT_FOUND));
    log.info(accountEntity.getCreatedAt().toString());
    AccountDTO accountDTO = new AccountDTO();
    BeanUtils.copyProperties(accountEntity, accountDTO);
    return Result.respond(accountDTO);
  }

  /** @Description: 策略模式测试 */
  @PostMapping("/test/strategy/{number}")
  public Result<String> testStrategy(
      @PathVariable String number, @RequestBody AccountDTO accountDTO) {
    return Result.respond(documentStrategyContainer.handle(number, accountDTO));
  }

  /** @Description: 异步写测试 */
  @PostMapping("/insert/async")
  public void asyncInsert(@RequestBody AccountDTO accountDTO) {
    accountService.asyncSaveAccount(accountDTO);
  }

  /** @Description: 主数据事务提交后异步处理其他数据 */
  @PostMapping("/jpa/test")
  public void jpaTest(@RequestBody AccountDTO accountDTO) throws Exception {
    accountService.jpaTest(accountDTO);
  }
}
